<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import { NButton, NInput, NCard } from 'naive-ui';

// 画布大小和网格配置
const canvasWidth = 1200;
const canvasHeight = 800;
const gridSize = 20;

// 用于存储布局项，包含拖拽状态
const layout = ref([
  {
    type: NButton,
    props: { type: 'primary' },
    content: 'Default',
    position: { x: 50, y: 50 },
    events: {
      click: () => {
        console.log('Button clicked!');
      }
    }
  },
  {
    type: NInput,
    props: { placeholder: '请输入内容' },
    model: ref(''),
    position: { x: 150, y: 150 },
    events: {
      updateValue: (newValue: string) => {
        console.log('Input value updated:', newValue);
      }
    }
  }
]);

// 当前拖拽的组件
const draggingItem = ref<null | { index: number, offsetX: number, offsetY: number }>(null);

// 吸附功能的辅助函数
const snapToGrid = (x: number, y: number) => {
  const snappedX = Math.round(x / gridSize) * gridSize;
  const snappedY = Math.round(y / gridSize) * gridSize;
  return { x: snappedX, y: snappedY };
};

// 画布的拖拽操作
const handleMouseDown = (event: MouseEvent, index: number) => {
  const item = layout.value[index];
  draggingItem.value = {
    index,
    offsetX: event.clientX - item.position.x,
    offsetY: event.clientY - item.position.y
  };
};

const handleMouseMove = (event: MouseEvent) => {
  if (draggingItem.value) {
    const item = layout.value[draggingItem.value.index];
    let newX = event.clientX - draggingItem.value.offsetX;
    let newY = event.clientY - draggingItem.value.offsetY;

    // 吸附到网格
    const snappedPosition = snapToGrid(newX, newY);
    item.position.x = snappedPosition.x;
    item.position.y = snappedPosition.y;
  }
};

const handleMouseUp = () => {
  draggingItem.value = null;
};

// 监听鼠标事件
onMounted(() => {
  window.addEventListener('mousemove', handleMouseMove);
  window.addEventListener('mouseup', handleMouseUp);
});
</script>

<template>
  <div class="canvas-container" style="position: relative; width: 100%; height: 100%; overflow: hidden;">
    <!-- 标尺 -->
    <div class="ruler horizontal">
      <div v-for="i in Math.ceil(canvasWidth / gridSize)" :key="i" class="ruler-tick" :style="{ left: `${i * gridSize}px` }">
        <span>{{ i }}</span>
      </div>
    </div>
    <div class="ruler vertical">
      <div v-for="i in Math.ceil(canvasHeight / gridSize)" :key="i" class="ruler-tick" :style="{ top: `${i * gridSize}px` }">
        <span>{{ i }}</span>
      </div>
    </div>

    <!-- 画布 -->
    <div class="canvas" style="position: absolute; width: 100%; height: 100%; background-color: #fff; border: 1px solid #ccc; overflow: hidden;">
      <!-- 网格 -->
      <div
          v-for="i in Math.ceil(canvasHeight / gridSize)"
          :key="'grid-row-' + i"
          class="grid-line"
          :style="{ top: (i * gridSize) + 'px', left: 0, width: '100%', height: '1px' }"
      ></div>
      <div
          v-for="i in Math.ceil(canvasWidth / gridSize)"
          :key="'grid-col-' + i"
          class="grid-line"
          :style="{ left: (i * gridSize) + 'px', top: 0, width: '1px', height: '100%' }"
      ></div>
    </div>

    <!-- 动态渲染组件 -->
    <div v-for="(item, index) in layout" :key="index" :style="{ position: 'absolute', left: item.position.x + 'px', top: item.position.y + 'px' }">
      <component
          :is="item.type"
          v-bind="item.props"
          v-on="item.events"
          @mousedown="handleMouseDown($event, index)"
      >
        <template v-if="item.content">
          {{ item.content }}
        </template>
      </component>
    </div>
  </div>
</template>

<style scoped>
.canvas-container {
  position: relative;
  width: 100%;
  height: 100%;
  background-color: #fafafa;
}

.ruler {
  position: absolute;
  z-index: 1;
  background-color: #f0f0f0;
  border: 1px solid #ccc;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ruler.horizontal {
  top: 0;
  left: 0;
  right: 0;
  height: 20px;
  font-size: 12px;
}

.ruler.vertical {
  top: 0;
  left: 0;
  width: 20px;
  bottom: 0;
  font-size: 12px;
}

.ruler-tick {
  position: absolute;
  height: 100%;
  border-left: 1px solid #ccc;
}

.ruler-tick span {
  position: absolute;
  top: -15px;
  left: -8px;
  font-size: 10px;
  color: #888;
}

.canvas {
  position: absolute;
  top: 0;
  left: 0;
  background-color: #fff;
}

.grid-line {
  position: absolute;
  background-color: #ddd;
}

.grid-line:nth-of-type(odd) {
  opacity: 0.5;
}

</style>
